05 / 15

What is the difference between the microtask queue and the macrotask (callback) queue?

JavaScript's event loop manages two distinct task queues: the microtask queue and the macrotask (callback) queue. The microtask queue handles high-priority, short operations that need to be executed immediately after the current operation completes, before any rendering or new macrotasks. The macrotask queue handles lower-priority, longer operations that are executed in rounds, with the event loop taking one macrotask per iteration. The critical difference is that microtasks are processed in a single batch until the queue is empty, whereas macrotasks are processed one at a time, with the event loop potentially rendering the page between them. This ordering is fundamental to understanding JavaScript's asynchronous behavior and avoiding subtle bugs.

Event Loop Execution Order Example
Characteristics of Macrotask Queue
  1. 1

    Also known as: Task queue, callback queue, event queue

  2. 2

    Sources: setTimeout, setInterval, setImmediate (Node.js), I/O operations, UI rendering, message events, requestAnimationFrame

  3. 3

    Processing model: One macrotask is taken from the queue per event loop iteration

  4. 4

    Priority: Lower priority than microtasks

  5. 5

    Browser rendering: May occur between macrotasks

  6. 6

    Order: Tasks are executed in FIFO (First In, First Out) order

Characteristics of Microtask Queue
  1. 1

    Also known as: Job queue, microtask queue

  2. 2

    Sources: Promise callbacks (then, catch, finally), queueMicrotask, MutationObserver, process.nextTick (Node.js)

  3. 3

    Processing model: All microtasks are processed until the queue is empty before moving to the next macrotask

  4. 4

    Priority: Higher priority than macrotasks

  5. 5

    Browser rendering: Microtasks block rendering until the queue is empty

  6. 6

    Potential issue: Recursively adding microtasks can cause infinite loops and freeze the page

Real-World Impact of Microtask Queue
Event Loop Priority Order
  1. 1
    1. Execute all synchronous code in the current call stack
  2. 2
    1. Process all microtasks (Promise callbacks, queueMicrotask, MutationObserver) until queue is empty
  3. 3
    1. Perform one macrotask from the macrotask queue
  4. 4
    1. Possibly render the page (browser specific)
  5. 5
    1. Return to step 2 (process microtasks again) if any were added during macrotask
  6. 6
    1. Repeat the loop
Complex Interleaving Example

Understanding the microtask/macrotask distinction is crucial for avoiding subtle bugs in asynchronous JavaScript. For example, Promise callbacks and queueMicrotask are processed before setTimeout even with a 0ms delay, which can lead to unexpected ordering. Additionally, while macrotasks allow the browser to render between them (keeping the UI responsive), microtasks can block rendering if they are continuously added, potentially causing performance issues. Modern JavaScript patterns like React's batching rely on microtasks to batch state updates efficiently before rendering.